import {
  ClusterOutlined,
  SwapOutlined,
  ReloadOutlined,
  PoweroffOutlined,
  LogoutOutlined,
} from '@ant-design/icons'
import { keywordCompare } from '@gnlab/utils'
import { message } from 'antd'
import { OrderedSet } from 'immutable'
import { type Dispatch, type SetStateAction } from 'react'
import services from '@/services'
import type { Account, BaseAccount } from '@/services/auth'
import type { AccountGroup } from '@/services/features/accounts'
import type { AccountQywx } from '@/services/qywxs'
import { AccountQywxStatus } from '@/services/qywxs'

function useLoading() {
  const [loading, setLoading] = useState(false)

  const startLoad = useCallback(async function <T>(promise: Promise<T>) {
    setLoading(true)
    const start = Date.now()
    const res = await promise
    const finish = Date.now()

    const minDuration = 1000 // loading 状态结束最小时间，如果在此之前结束，会等达到此时间才实际改变状态
    const timeout = Math.max(0, minDuration - (finish - start))
    setTimeout(() => setLoading(false), timeout)

    return res
  }, [])

  return {
    loading,
    startLoad,
  }
}

/**
 * 返回账号及对应的企业微信数据
 */
export function useAccountAndQywxs() {
  const [accounts, setAccounts] = useState<Account[]>([])
  const [accountQywxMap, setAccountQywxMap] = useState<Map<string, AccountQywx[]>>(new Map()) // 各账号下登录的企业微信   accountId => qywx[]

  const { loading, startLoad } = useLoading()
  const loadQywxs = useCallback(async () => {
    const res = await startLoad(services.qywxs.getAllAccountQywxs(false, true))
    setAccounts(res.accounts)

    const map = new Map<string, AccountQywx[]>()
    for (const qywx of res.qywxs) {
      if (map.has(qywx.accountId)) map.get(qywx.accountId)!.push(qywx)
      else map.set(qywx.accountId, [qywx])
    }
    setAccountQywxMap(map)
  }, [startLoad])

  useEffect(() => {
    void loadQywxs()
    const intervalId = setInterval(() => void loadQywxs(), 5 * 1000) // 定时刷新数据
    return () => clearInterval(intervalId)
  }, [loadQywxs])

  return {
    accounts,
    accountQywxMap,
    loadQywxs,
    loading,
  }
}

/**
 * 筛选账号
 */
export function useAccountFilter(accounts: Account[]) {
  const [groups, setGroups] = useState<AccountGroup[] | null>(null)
  const [selectedGroup, setSelectedGroup] = useState<null | AccountGroup>(null)
  useEffect(() => {
    void services.features.accounts.getGroups().then(_groups => {
      setGroups(_groups)
    })
  }, [])

  // Map<accountId, AccountGroup[]>
  const accountGroupsMap = useMemo(() => {
    return new Map(
      accounts.map(account => [
        account.id,
        (groups ?? []).filter(group => group.accountIds.includes(account.id)),
      ]),
    )
  }, [accounts, groups])

  const filteredAccounts = useMemo(() => {
    if (selectedGroup) {
      return accounts.filter(account => selectedGroup.accountIds.includes(account.id))
    } else {
      return accounts
    }
  }, [accounts, selectedGroup])

  return {
    groups,
    selectedGroup,
    setSelectedGroup,
    filteredAccounts,
    accountGroupsMap,
  }
}

/**
 * 选择账号及筛选企业微信
 */
interface QywxFilterState {
  accountId: string
  mode: 'online' | 'offline'
  search: string
}
function qywxFilterReducer(
  state: QywxFilterState,
  action:
    | { type: 'select-account'; id: string }
    | { type: 'set-mode'; mode: 'online' | 'offline' }
    | { type: 'set-search'; search: string },
) {
  switch (action.type) {
    case 'select-account':
      return {
        ...state,
        accountId: action.id,
        search: '',
      }
    case 'set-mode':
      return { ...state, mode: action.mode }
    case 'set-search':
      return { ...state, search: action.search }
    default:
      throw new Error()
  }
}
function getInitialQywxFilterState({
  accounts,
  accountQywxMap,
}: {
  accounts: Account[]
  accountQywxMap: Map<string, AccountQywx[]>
}): QywxFilterState {
  const accountId = accounts[0]?.id ?? '' // 默认选中第一个账号

  const qywxs = accountQywxMap.get(accountId)
  const mode =
    !qywxs || qywxs.find(v => v.status === AccountQywxStatus.Online) ? 'online' : 'offline'

  return { accountId, mode, search: '' }
}

export function useQywxFilter(
  accounts: Account[],
  accountQywxMap: Map<string, AccountQywx[]>,
  rebooting: OrderedSet<string>,
) {
  const [{ accountId: preferAccountId, mode, search }, dispatch] = useReducer(
    qywxFilterReducer,
    { accounts, accountQywxMap },
    getInitialQywxFilterState,
  )

  const accountId = useMemo(
    () =>
      // 若 accounts 列表变化，原选中的 accountId 不在列表里了，返回列表第一个账号
      accounts.find(v => v.id === preferAccountId) ? preferAccountId : accounts[0]?.id ?? '',
    [accounts, preferAccountId],
  )

  // 当前选中账号的企业微信列表
  const accountQywxs = useMemo(
    () => accountQywxMap.get(accountId) ?? [],
    [accountQywxMap, accountId],
  )

  const showingQywxs = useMemo(() => {
    const filtered = accountQywxs.filter(qywx => {
      const modeMatch = (mode === 'online') === (qywx.status === AccountQywxStatus.Online)
      const searchMatch =
        !search || keywordCompare(search, `${qywx.hostname}${qywx.wxid}${qywx.friendlyFullName}`)
      const notRebooting = !rebooting.has(qywx.wxid) // 过滤掉重启中的企业微信（后续会根据情况添加到列表最前面）
      return modeMatch && searchMatch && notRebooting
    })
    const rebootingQywxs =
      mode === 'online'
        ? rebooting
            .toArray()
            .map(wxid => accountQywxs.find(v => v.wxid === wxid))
            .filter((v): v is AccountQywx => !!v)
        : []
    return [...rebootingQywxs, ...filtered]
  }, [mode, search, accountQywxs, rebooting])

  const count = useMemo(() => {
    const online =
      accountQywxs.filter(
        qywx => qywx.status === AccountQywxStatus.Online && !rebooting.has(qywx.wxid),
      ).length + rebooting.size
    const offline = accountQywxs.filter(
      qywx => qywx.status !== AccountQywxStatus.Online && !rebooting.has(qywx.wxid),
    ).length
    return { online, offline }
  }, [accountQywxs, rebooting])

  return {
    accountId,
    mode,
    search,
    dispatch,
    accountQywxs,
    showingQywxs,
    count,
  }
}

/**
 * 处理企业微信的选中状态
 * 因为转交操作的限制，仅支持选中同一个账号下的企业微信（不支持跨账号选中企业微信）
 */
export function useChooseQywxs(qywxs: AccountQywx[]) {
  const [manualChoosed, setChoosed] = useState(OrderedSet<string>())

  // 仅列出最新的 qywxs 列表里有的（例如切换了选中的账号、企业微信转交/退出等，都会改变列表）
  const choosed = useMemo(
    () => manualChoosed.filter(wxid => qywxs.find(v => v.wxid === wxid)),
    [qywxs, manualChoosed],
  )

  const switchChoose = useCallback((item: AccountQywx) => {
    setChoosed(choosed =>
      choosed.has(item.wxid) ? choosed.remove(item.wxid) : choosed.add(item.wxid),
    )
  }, [])

  // 0: 没有选中， 1: 全部选中，2: 部分选中
  const chooseAllStatus = qywxs.length === choosed.size ? 1 : choosed.size ? 2 : 0
  // 全选/反选
  const switchChooseAll = useCallback(() => {
    setChoosed(
      chooseAllStatus === 0 || chooseAllStatus === 2
        ? OrderedSet(qywxs.map(qywx => qywx.wxid))
        : OrderedSet(),
    )
  }, [chooseAllStatus, qywxs])
  // 全部取消选中
  const resetChoose = useCallback(() => setChoosed(OrderedSet()), [])

  return {
    choosedQywxs: choosed,
    switchChooseQywx: switchChoose,
    chooseAllStatus,
    switchChooseAll,
    resetChoose,
  }
}

interface BareAction {
  icon: React.ReactNode
  title: string
  status: Set<AccountQywxStatus>
  needConfirm: boolean
  execute: (targetWxids: string[]) => void
}
export interface Action extends Exclude<BareAction, 'execute'> {
  execute: () => void
}

export function useQywxActions(
  qywxs: AccountQywx[], // 未经过滤的 qywxs 列表
  accounts: Account[],
  loadQywxs: () => void,
  transferChooseAccount: (targetWxids: string[]) => void,
  rebooting: OrderedSet<string>,
  // 待后续增加对 rebooting 的更新机制
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  setRebooting: Dispatch<SetStateAction<OrderedSet<string>>>,
) {
  const getQywxs = useCallback(
    (wxids: string[]) => {
      return wxids
        .map(wxid => qywxs.find(qywx => qywx.wxid === wxid))
        .filter((qywx): qywx is AccountQywx => !!qywx)
    },
    [qywxs],
  )

  const executeContainerAction = useCallback(
    (action: 'reboot' | 'offline' | 'online', targetWxids: string[]) => {
      void services.qywxs
        .adminContainerAction(
          action,
          getQywxs(targetWxids).map(v => v.hostname),
        )
        .then(res => {
          if (!res.success) void message.warning(res.error)
          void loadQywxs()
        })
    },
    [getQywxs, loadQywxs],
  )

  const mounted = useRef(true)
  useEffect(() => {
    return () => {
      mounted.current = false
    }
  }, [])

  const transferQywxs = useCallback(
    async (toAccount: BaseAccount, targetWxids: string[]) => {
      const targets = getQywxs(targetWxids)
      if (!targets.length) return

      const fromAccount = accounts.find(ac => ac.id === targets[0]!.accountId)!
      const result = await services.qywxs.transfers.transfer(targets, toAccount, fromAccount)
      void loadQywxs()
      return result
    },
    [getQywxs, loadQywxs, accounts],
  )

  // =======================================

  const actions: BareAction[] = useMemo(() => {
    const reboot = {
      icon: <ReloadOutlined />,
      title: '重启',
      status: new Set([AccountQywxStatus.Online]),
      needConfirm: true,
      execute(targetWxids: string[]) {
        // TODO: 后续增加对 rebooting 的更新机制
        executeContainerAction('reboot', targetWxids)
      },
    }
    const offline = {
      icon: <LogoutOutlined />,
      title: '下线',
      status: new Set([AccountQywxStatus.Online]),
      needConfirm: true,
      execute: executeContainerAction.bind(null, 'offline'),
    }
    const logout = {
      icon: <ClusterOutlined />,
      title: '登出',
      status: new Set([AccountQywxStatus.Online]),
      needConfirm: true,
      execute(targetWxids: string[]) {
        services.qywxs.adminLogout(getQywxs(targetWxids))
        loadQywxs()
      },
    }
    const transfer = {
      icon: <SwapOutlined />,
      title: '转交',
      status: new Set([AccountQywxStatus.Online]),
      needConfirm: false,
      execute: transferChooseAccount,
    }
    const online = {
      icon: <PoweroffOutlined />,
      title: '上线',
      status: new Set([AccountQywxStatus.Offline]),
      needConfirm: true,
      execute: executeContainerAction.bind(null, 'online'),
    }
    return [reboot, offline, logout, transfer, online]
  }, [executeContainerAction, getQywxs, loadQywxs, transferChooseAccount])

  const getActions = useCallback(
    (targets: AccountQywx[]): Action[] => {
      const targetWxids = targets.map(v => v.wxid)
      return filterActions(actions, targets, rebooting).map(action => ({
        ...action,
        execute() {
          action.execute(targetWxids)
        },
      }))
    },
    [rebooting, actions],
  )

  return {
    getActions,
    transferQywxs,
  }
}

// 过滤出对目标企业微信可用的操作
function filterActions(
  actions: BareAction[],
  targets: AccountQywx[],
  rebooting: OrderedSet<string>,
) {
  if (targets.find(qywx => rebooting.has(qywx.wxid))) return [] // 重启中的企业微信不允许执行任何操作
  return actions.filter(action => matchStatus(action.status, targets))
}

// 判断 targets 里的企业微信是否全部符合 status 要求
function matchStatus(status: Set<AccountQywxStatus>, targets: AccountQywx[]) {
  return targets.length && targets.every(qywx => status.has(qywx.status))
}
